﻿package com.neriksworkshop.lib.colourLovers.core
{
	import com.adobe.serialization.json.JSON;
	import com.neriksworkshop.lib.colourLovers.events.RequestEvent;
	import com.neriksworkshop.lib.colourLovers.items.Color;
	import com.neriksworkshop.lib.colourLovers.items.IGraphicItem;
	import com.neriksworkshop.lib.colourLovers.items.IItem;
	import com.neriksworkshop.lib.colourLovers.items.Palette;
	import com.neriksworkshop.lib.colourLovers.items.Pattern;
	import com.neriksworkshop.lib.colourLovers.params.Params;
	import com.neriksworkshop.lib.colourLovers.requests.ColorRequest;
	import com.neriksworkshop.lib.colourLovers.requests.IRequest;
	import com.neriksworkshop.lib.colourLovers.requests.PaletteRequest;
	import com.neriksworkshop.lib.colourLovers.requests.params.Format;
	import com.neriksworkshop.lib.colourLovers.requests.params.OrderCol;
	import com.neriksworkshop.lib.colourLovers.requests.PatternRequest;
	import com.neriksworkshop.lib.colourLovers.UIdURLLoader;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLRequest;
	import flash.utils.describeType;
	
	/**
	 * ...
	 * @author ...
	 */
	public class AbstractRequest extends EventDispatcher implements IRequest
	{
	
		protected var _params:Object = new Object();		
		protected var _items:/*IItem*/Array;
		protected var _baseServiceUrl:String;
		
		protected var _extraData:*;
		
		private var _xmlData:XML;
		private var _jsonData:Object;
		
		protected static const BASE_SERVICE_URL:String = "http://www.colourlovers.com/api";
		
		
		
		
		
		public function AbstractRequest(self:AbstractRequest) 
		{
			if (self != this) throw Params.ERROR_ABSTRACT_CLASS;
			
			_baseServiceUrl = BASE_SERVICE_URL;
			format = Format.FMT_JSON;
		}
		
		
		public function get serviceUrl():String 
		{
			return buildServiceUrl(); 
		}
		
		public function get xmlData():XML { return _xmlData; }	
		
		public function get jsonData():Object { return _jsonData; }
		
		public function get items():/*IItem*/Array { return _items; }
		
		
		public function get extraData():* { return _extraData; }
		
		public function set extraData(value:*):void 
		{
			_extraData = value;
		}
		

		
		
		
		
		
		
		
		
		public function get format():String { return _params.format; }
		
		public function set format(value:String):void 
		{
			_params.format = value;
		}		
		
		public function get orderCol():String { return _params.orderCol; }
		
		public function set orderCol(value:String):void 
		{
			_params.orderCol = value;
		}
		
		public function get sortBy():String { return _params.sortBy; }
		
		public function set sortBy(value:String):void 
		{
			_params.sortBy = value;
		}
		
		public function get numResults():uint { return _params.numResults; }
		
		public function set numResults(value:uint):void 
		{
			_params.numResults = value;
		}
		
		public function get resultOffset():uint { return _params.resultOffset; }
		
		public function set resultOffset(value:uint):void 
		{
			_params.resultOffset = value;
		}
		
		

		

		
		
		
		public function load():int
		{
			var ul:UIdURLLoader = new UIdURLLoader();
			var ur:URLRequest = new URLRequest(serviceUrl);

			if (format == Format.FMT_XML)
			{
				ul.addEventListener(Event.COMPLETE, onXMLLoaded);
			}
			else if (format == Format.FMT_JSON)
			{
				ul.addEventListener(Event.COMPLETE, onJSONLoaded);
			}

			ul.load(ur);
			return ul.UId;
		}
		
		
		
		protected function onXMLLoaded(e:Event):void 
		{
			_xmlData = XML(UIdURLLoader(e.target).data);
			_jsonData = null;

			_items = new Array();
			
			for each (var itemXML:XML in _xmlData.children()) 
			{
				var newItem:IItem = createAssociatedItem();
				
				newItem.buildFromData(itemXML);
				_items.push(newItem);
			}
									
			dispatchRequestEvent(UIdURLLoader(e.target).UId);
			
		}
		
		
		private function onJSONLoaded(e:Event):void 
		{
			//trace("JSON:::\m", UIdURLLoader(e.target).data)

			_jsonData = JSON.decode(UIdURLLoader(e.target).data);
			_xmlData = null;
			
			_items = new Array();
			
			for (var name:String in _jsonData) 
			{
				var newItem:IItem = createAssociatedItem();
				
				newItem.buildFromData(_jsonData[name]);
				_items.push(newItem);				
			}
			
			dispatchRequestEvent(UIdURLLoader(e.target).UId);
			
		}
		
				
		private function createAssociatedItem():IItem
		{
			var newItem:IItem;
			if (this is ColorRequest)	newItem = new Color();
			if (this is PaletteRequest)	newItem = new Palette();
			if (this is PatternRequest)	newItem = new Pattern();
			return newItem;
		}
		
		
		private function dispatchRequestEvent(eventUId:int):void
		{			
			var evtName:String = (_items.length == 0) ? RequestEvent.NO_RESULTS : RequestEvent.RESULTS;
			dispatchEvent(new RequestEvent(eventUId, this, evtName));			
			
		}
	
		
		protected function buildServiceUrl():String
		{
			//TODO TOFINISH output correct request url with array/boolean/etc values
			
		
			var _serviceUrl:String = _baseServiceUrl;
			
			//FIXME random request --> stack overflow
			if (orderCol == OrderCol.RANDOM)
			{
				_serviceUrl += "/random";
				return serviceUrl;
			}
			
			_serviceUrl += "?";
			var args:Array = new Array();
			
			for (var param:String in _params) 
			{
				if (_params[param]) 
				{
					
					//trace(param, _params[param], _params[param] is Array)
					
					if (isEmpty(_params[param])) continue;
					
					var value:String;
					
					if 		(_params[param] is Boolean) 	value = (_params[param]) ? "1" : "0";
					else if (_params[param] is Array) 
					{
						var arr:Array = (_params[param] as Array);
						var arrLength:int = arr.length;
						
						//TODO remove properly empty array cells
						for (var i:int = 0; i < arrLength; i++) 
						{
							if (isEmpty(arr[i])) 	{ arr.splice(i, 1); i++ }
							else 					arr[i] = encodeURI(String(arr[i])); 
						}
						
						if (param == "keywords") 			value = arr.join("+");
						else								value = String(arr);
					}
					else if (_params[param] is String) 		value = encodeURI(_params[param]);
					else									value = String(_params[param]);
					
					args.push(param + "=" + value);
					//_serviceUrl += param + "=" + value + "&";
				}
				//if (_params[param] is Array) 		_serviceUrl += 
			}
			
			_serviceUrl += args.join("&");
			
			//trace(_serviceUrl);
			return _serviceUrl;
		}
		
		
		
		private function isEmpty(item:*):Boolean
		{
			if (!item) return true;
			if ((item is String && item == "") || (item is Array && (item as Array).length == 0)) return true;
			return false;
		}
		
		
	}
	
}